import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
  HttpStatus,
  HttpException
} from '@nestjs/common'
import { Reflector } from '@nestjs/core'

import { UserService } from 'src/user/user.service'
import { LoggerService } from 'src/logger/logger.service'
import { EasyRequest } from 'types/global'
import { Response } from 'express'
@Injectable()
export class LoggerGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector,
    private readonly loggerService: LoggerService
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<EasyRequest>()
    const response = context.switchToHttp().getResponse()

    // 捕获响应数据
    let responseData = ''
    const originalWrite = response.write
    const originalEnd = response.end
    const time = Date.now()
    response.write = function (
      chunk: any,
      encoding?: BufferEncoding,
      callback?: (error?: Error) => void
    ): boolean {
      if (chunk) {
        responseData += chunk.toString(encoding)
      }
      return originalWrite.apply(response, arguments as any)
    }

    response.end = function (
      chunk?: any,
      encoding?: BufferEncoding,
      callback?: (error?: Error) => void
    ): Response {
      if (chunk) {
        responseData += chunk.toString(encoding)
      }
      return originalEnd.apply(response, arguments as any) as Response
    }

    // 记录用户访问日志
    response.on('finish', () => {
      const responseTime = Date.now() - time
      const { method, url, user, headers } = request
      const userAgent = headers['user-agent'] || ''

      if (!user) return

      const prefixMsg = this.reflector.get<string>(
        'prefixMsg',
        context.getHandler()
      )

      let param = ''
      if (method === 'GET') {
        param = JSON.stringify(request.query)
      } else {
        param = JSON.stringify(request.body)
      }

      const { code, message } = JSON.parse(responseData)

      this.loggerService.log({
        name: prefixMsg,
        ip: this.getRealIp(request),
        method,
        url,
        statusCode: code,
        responseData: this.getMessage(message),
        responseTime,
        userAgent,
        userId: user.userId,
        userName: user.name,
        param
      })
    })
    return true
  }

  /**
   * @description: 处理messgae，如果数组则转成字符串；分割，如果字符串直接返回
   */
  private getMessage(message: any): string {
    if (Array.isArray(message)) {
      return message.join(' ; ')
    } else if (typeof message === 'string') {
      return message
    } else {
      return JSON.stringify(message)
    }
  }

  /**
   * @description: 获取客户端真实 IP
   * @param {EasyRequest} req
   */
  private getRealIp(req: EasyRequest): string {
    const result =
      req.headers['x-forwarded-for'] ||
      req.headers['x-real-ip'] ||
      req.socket.remoteAddress ||
      req.ip
    return Array.isArray(result) ? result[0] : result
  }
}
